﻿// Original author contact info: Owen Emlen (owene_1998@yahoo.com)
// Note: other individuals may also have contributed to this code
// Project hosted on CodePlex.com as of 1/10/2009 at http://www.codeplex.com/EmlenMud
using System.Runtime.Serialization;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Threading;
using BrainTechLLC.ThreadSafeObjects;
using System.Text;
#if USE_HYPER
using Hyper.ComponentModel;
#endif

namespace BrainTechLLC.Logging
{
    /// <summary>
    /// Provides buffered logging to a file
    /// </summary>
    [TypeDescriptionProvider(typeof(HyperTypeDescriptionProvider))]
    [Serializable]
    [DataContract]
    public class FileLogger : LoggerBase, ILogger
    {
        private readonly int LogEntriesBeforeWrite = 10;//BrainTechLLC.NonSilverlightCompatible.Properties.Settings.Default.MinimumEntriesBeforeLogWrite;
        private readonly int LogEntriesPerFile = 50000;//BrainTechLLC.NonSilverlightCompatible.Properties.Settings.Default.LogEntriesPerFile;

        private int _currentLogNumber;
        private string _currentLogFileNameCached;
        private int _entriesWrittenToCurrentLogFile;

        public string FileNameBase { get; set; }

        public static void CreateAndRegisterFileLogger(string path, string fileNameBase)
        {
            if (path.EndsWith("\\"))
                path = path.Substring(0, path.Length - 1);

            if (!Directory.Exists(path))
                Directory.CreateDirectory(path);

            FileLogger logger = new FileLogger(path + "\\" + fileNameBase);
            logger.BeginLogging();
            GlobalLogger.RegisterLogger(logger);
        }

        public FileLogger()
            : base()
        {
        }

        public FileLogger(string fileNameBase)
            : this()
        {
            FileNameBase = fileNameBase;
        }

        public string CurrentLogFileName
        {
            get
            {
                if (_currentLogFileNameCached == null)
                    _currentLogFileNameCached = FileNameBase + _currentLogNumber.ToString() + ".txt";

                return _currentLogFileNameCached;
            }
        }

        protected void IncrementCurrentLogFileNumber()
        {
            _currentLogNumber++;
            _currentLogFileNameCached = null;
        }

        protected void MoveToNextFreeLogFileNumber()
        {
            while (!WantExit && File.Exists(CurrentLogFileName)) { IncrementCurrentLogFileNumber(); }
        }

        protected override void LogListener()
        {
            MoveToNextFreeLogFileNumber();
            List<LogMessage> logEntries = new List<LogMessage>();

            try
            {
                while (!WantExit)
                {
                    DateTime beginTry = DateTime.Now;

                    while (!WantExit && _logOutput.Count < LogEntriesBeforeWrite && beginTry.AddSeconds(2D) < DateTime.Now) { Thread.Sleep(200); }

                    while (!WantExit && _logOutput.DequeueMultiple(logEntries, LogEntriesBeforeWrite) > 0)
                    {
                        if (_entriesWrittenToCurrentLogFile >= LogEntriesPerFile) { IncrementCurrentLogFileNumber(); }
                        WriteLogEntries(logEntries);
                        logEntries.Clear();
                    }

                    Thread.Sleep(200);
                }
            }
            catch (ThreadAbortException)
            {
                Thread.CurrentThread.IsBackground = false;
                while (_logOutput.DequeueMultiple(logEntries, LogEntriesBeforeWrite) > 0)
                {
                    WriteLogEntries(logEntries);
                    logEntries.Clear();
                }
                Thread.CurrentThread.IsBackground = true;
            }
            catch (Exception exOther)
            {
                Console.WriteLine(exOther.ToString());
            }
            finally
            {
                Thread.CurrentThread.IsBackground = false;
                while (_logOutput.DequeueMultiple(logEntries, LogEntriesBeforeWrite) > 0)
                {
                    WriteLogEntries(logEntries);
                    logEntries.Clear();
                }
                Thread.CurrentThread.IsBackground = true;
            }
        }

        protected void WriteLogEntries(List<LogMessage> logEntries)
        {
            try
            {
                StringBuilder sb = new StringBuilder();
                logEntries.ForEach(logEntry => sb.AppendLine(logEntry.ToString()));
                File.AppendAllText(CurrentLogFileName, sb.ToString());
                _entriesWrittenToCurrentLogFile += logEntries.Count;                
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }
    }

#if NO_SILVERLIGHT
    public class RuntimeProblemLog
    {
        public static RuntimeProblemLog _instance;

        public static RuntimeProblemLog Instance
        {
            get
            {
                if (_instance == null)
                    Interlocked.CompareExchange<RuntimeProblemLog>(ref _instance, new RuntimeProblemLog(), null);

                return _instance;
            }
        }

        public FileLogger _logger;

        public RuntimeProblemLog()
        {
            _logger = new FileLogger("C:\\ProblemLog");
            _logger.BeginLogging();
        }

        ~RuntimeProblemLog()
        {
            _logger.WantExit = true;
        }

        public static void Log(string messageType, string message, LogSeverity severity)
        {
            Instance._logger.Log(messageType, message, severity);
        }

        public static void LogProblem(string message)
        {
            Log("Runtime Problem", message, LogSeverity.Warning);
        }
    }
#endif
}